<?php

namespace app\socket\controller;

use PHPSocketIO\SocketIO;
use Workerman\Worker;

class IOAdmin
{
    // 全局数组保存uid在线数据
    protected $uidConnectionMap = array();
    //后台登录时保存数据
    protected $uidDoMap = array();
    /**
     * 架构函数
     * @access public
     */
    public function __construct()
    {
        $this->init();
    }

    public function init()
    {
        $sender_io = new SocketIO(PORT);
        // 客户端发起连接事件时，设置连接socket的各种事件回调
        $sender_io->on('connection', function ($socket) {
            // 当客户端发来登录事件时触发
            $socket->on('login', function ($uid) use ($socket) {
                if(isset($socket->uid)){
                    return;
                }
                $this->uidConnectionMap[$uid] = $socket->uid = $uid;
                // 将这个连接加入到uid分组，方便针对uid推送数据
                $socket->join($uid);
                // 登录时后台会广播
                if (isset($this->uidDoMap[$uid]['act'])&&$this->uidDoMap[$uid]['act'] == 'login') {
                    $message['type'] = 'login';
                    $message['msg'] = $this->uidDoMap[$uid]['remark'];
                    $socket->broadcast->emit("new_msg",json_encode($message));
                    unset($this->uidDoMap[$uid]);
                }
            });
            // 当客户端断开连接是触发（一般是关闭网页或者跳转刷新导致）
            $socket->on('disconnect', function () use ($socket) {
                if (!isset($socket->uid) || !isset($this->uidConnectionMap[$socket->uid])) {
                    return;
                }
                // 登出时后台广播
                if (isset($this->uidDoMap[$socket->uid]['act'])&&$this->uidDoMap[$socket->uid]['act'] == 'logout') {
                    $message['type'] = 'logout';
                    $message['msg'] = $this->uidDoMap[$socket->uid]['remark'];
                    $socket->broadcast->emit("new_msg",json_encode($message));
                    unset($this->uidDoMap[$socket->uid]);
                }
                unset($this->uidConnectionMap[$socket->uid]);
            });
        });

        // 当$sender_io启动后监听一个http端口，通过这个端口可以给任意uid或者所有uid推送数据
        $sender_io->on('workerStart', function () use($sender_io){
            // 监听一个http端口
            $inner_http_worker = new Worker(INNER_HTTP);
            // 当http客户端发来数据时触发
            $inner_http_worker->onMessage = function ($http_connection, $data)use($sender_io) {
                $_POST = $_POST ? $_POST : $_GET;
                $to = @$_POST['to'];
                // 推送数据的url格式 type=publish&to=uid&content=xxxx
                switch (@$_POST['type']) {
                    //登录通知
                    case 'login':
                    case 'logout':
                        if ($to){
                            $this->uidDoMap[$to] = json_decode($_POST['content'],true);
                            return $http_connection->send('ok');
                        }else{
                            return $http_connection->send('error');
                        }
                        break;
                    case 'publish':
                        $send_to = json_decode($to,true);
                        if($send_to===null){
                            return $http_connection->send('fail');
                        }
                        $message = @$_POST['content'];
                        $this->sendMessage($sender_io,$message,$send_to);
                        return $http_connection->send('ok');
                        break;
                }
                return $http_connection->send('fail');
            };
            // 执行监听
            $inner_http_worker->listen();
        });
        if (!defined('GLOBAL_START')) {
            Worker::runAll();
        }
    }

    /**
     * 群发信息
     * @param Object //消息
     * @param $message //消息
     * @param $send_to //指定人ID数组
     * @param $flag //true 发给指定人，false不发给指定人
     * @return  boolean
     * */
    private function sendMessage($sender_io,$message, $send_to = array(), $flag = true)
    {
        if (empty($send_to)) {
            $sender_io->emit('new_msg', $message);
            return true;
        }
        if (!empty($this->uidConnectionMap)) {
            foreach ($this->uidConnectionMap as $val) {
                if ($flag) {
                    if (in_array($val, $send_to)) {
                        var_dump($val);
                        $sender_io->to($val)->emit('new_msg', $message);
                    }
                } else {
                    if (!in_array($val, $send_to)) {
                        $sender_io->to($val)->emit('new_msg', $message);
                    }
                }
            }
            return true;
        }
        return false;
    }
}